{
 "cells": [
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 1.获取大模型",
   "id": "363b249946130ed0"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-19T03:10:35.472103Z",
     "start_time": "2025-10-19T03:10:17.895569Z"
    }
   },
   "cell_type": "code",
   "source": [
    "import dotenv\n",
    "from langchain_openai import ChatOpenAI\n",
    "import os\n",
    "dotenv.load_dotenv() #加载当前目录下的 .env 文件\n",
    "os.environ['OPENAI_API_KEY'] = os.getenv(\"DASHSCOPE_API_KEY\")\n",
    "os.environ['OPENAI_BASE_URL'] = os.getenv(\"DASHSCOPE_BASE_URL\")\n",
    "# 创建大模型实例\n",
    "# llm = ChatOpenAI(model=\"gpt-4o-mini\") # 默认使用 gpt-3.5-turbo\n",
    "llm = ChatOpenAI(model=\"qwen-max\") # 默认使用 gpt-3.5-turbo\n",
    "# llm = ChatOpenAI(model=\"deepseek-v3\") # 默认使用 gpt-3.5-turbo\n",
    "# 直接提供问题，并调用llm\n",
    "response = llm.invoke(\"什么是大模型？\")\n",
    "print(response)"
   ],
   "id": "6c2486f3a658147d",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "content='大模型通常指的是在机器学习，特别是深度学习领域中，参数量非常庞大的神经网络模型。这些模型往往拥有数亿、数十亿甚至更多数量级的参数。随着计算能力的增长和数据集规模的扩大，研究者们能够训练出越来越大的模型，以期获得更好的性能表现。\\n\\n大模型的一些特点包括：\\n\\n1. **高性能**：通过使用大量的参数，这些模型能够在各种任务上达到当前最好的性能水平。\\n2. **泛化能力强**：由于接受了大量数据的训练，大模型通常具有很好的泛化能力，即它们不仅能在训练时见过的数据上表现良好，在未见过的新数据上也能有不错的表现。\\n3. **需要强大算力支持**：训练这样大规模的模型需要消耗极大的计算资源，包括但不限于GPU、TPU等加速器的支持。\\n4. **应用广泛**：从自然语言处理（如文本生成、机器翻译）、计算机视觉到语音识别等多个领域都有广泛应用。\\n5. **持续学习与适应**：一些大模型还支持持续学习或增量学习，意味着它们可以根据新的数据不断更新自己的知识库，从而更好地适应环境变化。\\n\\n值得注意的是，尽管大模型带来了许多优势，但同时也面临着一些挑战，比如高昂的训练成本、能源消耗问题以及对环境的影响等。因此，在追求更强大的AI系统的同时，也需要考虑如何更加高效地利用资源，并探索可持续发展的解决方案。' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 293, 'prompt_tokens': 12, 'total_tokens': 305, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'qwen-max', 'system_fingerprint': None, 'id': 'chatcmpl-1a2dc6bf-61f7-4b10-a8e5-5ffea542fe61', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None} id='run--9b4aaffa-2b62-42a4-8916-50a08ed5dd42-0' usage_metadata={'input_tokens': 12, 'output_tokens': 293, 'total_tokens': 305, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}}\n"
     ]
    }
   ],
   "execution_count": 8
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 2.使用提示词模板",
   "id": "de241fe5b6b8a12c"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-19T03:26:26.044668Z",
     "start_time": "2025-10-19T03:26:08.844501Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "# 需要注意的一点是，这里需要指明具体的role，在这里是system和用户\n",
    "prompt = ChatPromptTemplate.from_messages([\n",
    "(\"system\", \"你是世界级的技术文档编写者\"),\n",
    "(\"user\", \"{input}\") # {input}为变量\n",
    "])\n",
    "# 我们可以把prompt和具体llm的调用和在一起。\n",
    "chain = prompt | llm\n",
    "message = chain.invoke({\"input\": \"大模型中的LangChain是什么?\"})\n",
    "print(message)\n",
    "# print(type(message))"
   ],
   "id": "c82dd880599133e8",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "content='LangChain 是一个用于开发和部署基于语言模型的应用程序的开源框架。它旨在简化使用大型语言模型（如GPT-3, GPT-4等）构建应用的过程，提供了一套工具和服务来帮助开发者更有效地集成这些强大的AI能力到他们的项目中。以下是关于LangChain的一些关键点：\\n\\n### 主要特点\\n\\n1. **模块化设计**：LangChain采用了模块化的设计理念，使得用户可以根据自己的需求选择性地使用不同组件。\\n2. **链式调用**：允许将多个步骤组合成链条，从而实现复杂的逻辑处理流程。\\n3. **记忆支持**：内置了对对话历史的记忆支持，有助于保持上下文连贯性。\\n4. **数据接入**：可以轻松地与外部数据源或API进行集成，增强了信息获取的能力。\\n5. **安全考量**：提供了多种机制来保护敏感信息，并确保符合隐私法规要求。\\n\\n### 应用场景\\n\\n- **聊天机器人**：通过整合各种功能插件，创建能够理解自然语言并作出适当回应的聊天助手。\\n- **内容生成**：利用预训练的语言模型来自动生成文章、报告等文本材料。\\n- **知识问答系统**：结合特定领域的知识库，快速准确地回答用户提出的问题。\\n- **代码辅助**：为程序员提供智能提示或自动完成代码片段的服务。\\n\\n### 使用方法简介\\n\\n首先需要安装`langchain`库，然后根据具体需求配置相应的组件。例如，如果想要构建一个简单的问答系统，可能会涉及到以下步骤：\\n- 初始化一个基础的语言模型实例。\\n- 定义问题解析器，用来从输入中提取出实际要询问的内容。\\n- 设定答案生成策略，比如直接由模型生成答案或是查询数据库后再返回结果。\\n- 最后组装所有部分形成完整的链条，并启动服务监听用户请求。\\n\\n总之，LangChain 提供了一个灵活且强大的平台，让即使是不具备深厚机器学习背景的人也能轻松地利用先进的语言技术创造出有价值的应用程序。随着社区贡献的增长和技术的进步，预计未来还将有更多创新性的应用场景出现。' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 434, 'prompt_tokens': 26, 'total_tokens': 460, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'qwen-max', 'system_fingerprint': None, 'id': 'chatcmpl-59ca8553-31c1-4f23-a044-580181e7c755', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None} id='run--47055ad8-9adb-43d0-a7e2-992713ad60dc-0' usage_metadata={'input_tokens': 26, 'output_tokens': 434, 'total_tokens': 460, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}}\n"
     ]
    }
   ],
   "execution_count": 72
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 3 使用输出解析器",
   "id": "727df859b960b803"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-19T03:25:05.846351Z",
     "start_time": "2025-10-19T03:25:01.570686Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_core.output_parsers import StrOutputParser,JsonOutputParser\n",
    "# 初始化模型\n",
    "llm = ChatOpenAI(model=\"qwen-max\")\n",
    "# 创建提示模板\n",
    "prompt = ChatPromptTemplate.from_messages([\n",
    "(\"system\", \"你是世界级的技术文档编写者。\"),\n",
    "(\"user\", \"{input}\")\n",
    "])\n",
    "# 使用输出解析器\n",
    "# output_parser = StrOutputParser()\n",
    "output_parser = JsonOutputParser()\n",
    "# 将其添加到上一个链中\n",
    "# chain = prompt | llm\n",
    "chain = prompt | llm | output_parser\n",
    "# 调用它并提出同样的问题。答案是一个字符串，而不是ChatMessage\n",
    "# chain.invoke({\"input\": \"LangChain是什么?\"})\n",
    "chain.invoke({\"input\": \"LangChain是什么? 用JSON格式回复，问题用question，回答用answer\"})"
   ],
   "id": "694e9b2ef6f1afa2",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'question': 'LangChain是什么?',\n",
       " 'answer': 'LangChain是一个专注于语言模型（如GPT-3等）与外部数据源或工具集成的开源库。它允许开发者轻松地将语言模型连接到各种不同的数据存储、API接口或者其他服务，从而构建出更加复杂和功能丰富的应用程序。通过这种方式，LangChain使得基于语言模型的应用能够访问最新的信息、个人数据或者特定领域的知识，大大增强了这些应用的能力和实用性。'}"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 35
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 4 使用向量存储",
   "id": "27da9e63b81eecdf"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-19T03:37:19.879481Z",
     "start_time": "2025-10-19T03:37:19.605604Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 导入和使用 WebBaseLoader\n",
    "from langchain_community.document_loaders import WebBaseLoader\n",
    "import bs4\n",
    "loader = WebBaseLoader(\n",
    "web_path=\"https://www.gov.cn/xinwen/2020-06/01/content_5516649.htm\",\n",
    "bs_kwargs=dict(parse_only=bs4.SoupStrainer(id=\"UCAP-CONTENT\"))\n",
    ")\n",
    "docs = loader.load()\n",
    "# print(docs)\n",
    "# 对于嵌入模型，这里通过 API调用\n",
    "from langchain_openai import OpenAIEmbeddings\n",
    "embeddings = OpenAIEmbeddings(model=\"text-embedding-ada-001\")\n",
    "from langchain_community.vectorstores import FAISS\n",
    "from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
    "# 使用分割器分割文档\n",
    "text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)\n",
    "documents = text_splitter.split_documents(docs)\n",
    "print(len(documents))\n",
    "# 向量存储 embeddings 会将 documents 中的每个文本片段转换为向量，并将这些向量存储在FAISS向量数据库中\n",
    "vector = FAISS.from_documents(documents, embeddings)"
   ],
   "id": "e116ab9282523744",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n"
     ]
    },
    {
     "ename": "IndexError",
     "evalue": "list index out of range",
     "output_type": "error",
     "traceback": [
      "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[1;31mIndexError\u001B[0m                                Traceback (most recent call last)",
      "Cell \u001B[1;32mIn[94], line 20\u001B[0m\n\u001B[0;32m     18\u001B[0m \u001B[38;5;28mprint\u001B[39m(\u001B[38;5;28mlen\u001B[39m(documents))\n\u001B[0;32m     19\u001B[0m \u001B[38;5;66;03m# 向量存储 embeddings 会将 documents 中的每个文本片段转换为向量，并将这些向量存储在FAISS向量数据库中\u001B[39;00m\n\u001B[1;32m---> 20\u001B[0m vector \u001B[38;5;241m=\u001B[39m \u001B[43mFAISS\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mfrom_documents\u001B[49m\u001B[43m(\u001B[49m\u001B[43mdocuments\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43membeddings\u001B[49m\u001B[43m)\u001B[49m\n",
      "File \u001B[1;32mD:\\ProgramData\\miniconda3\\envs\\pyth310\\lib\\site-packages\\langchain_core\\vectorstores\\base.py:848\u001B[0m, in \u001B[0;36mVectorStore.from_documents\u001B[1;34m(cls, documents, embedding, **kwargs)\u001B[0m\n\u001B[0;32m    845\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28many\u001B[39m(ids):\n\u001B[0;32m    846\u001B[0m         kwargs[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mids\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;241m=\u001B[39m ids\n\u001B[1;32m--> 848\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mcls\u001B[39m\u001B[38;5;241m.\u001B[39mfrom_texts(texts, embedding, metadatas\u001B[38;5;241m=\u001B[39mmetadatas, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n",
      "File \u001B[1;32mD:\\ProgramData\\miniconda3\\envs\\pyth310\\lib\\site-packages\\langchain_community\\vectorstores\\faiss.py:1044\u001B[0m, in \u001B[0;36mFAISS.from_texts\u001B[1;34m(cls, texts, embedding, metadatas, ids, **kwargs)\u001B[0m\n\u001B[0;32m   1025\u001B[0m \u001B[38;5;250m\u001B[39m\u001B[38;5;124;03m\"\"\"Construct FAISS wrapper from raw documents.\u001B[39;00m\n\u001B[0;32m   1026\u001B[0m \n\u001B[0;32m   1027\u001B[0m \u001B[38;5;124;03mThis is a user friendly interface that:\u001B[39;00m\n\u001B[1;32m   (...)\u001B[0m\n\u001B[0;32m   1041\u001B[0m \u001B[38;5;124;03m        faiss = FAISS.from_texts(texts, embeddings)\u001B[39;00m\n\u001B[0;32m   1042\u001B[0m \u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[0;32m   1043\u001B[0m embeddings \u001B[38;5;241m=\u001B[39m embedding\u001B[38;5;241m.\u001B[39membed_documents(texts)\n\u001B[1;32m-> 1044\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mcls\u001B[39m\u001B[38;5;241m.\u001B[39m__from(\n\u001B[0;32m   1045\u001B[0m     texts,\n\u001B[0;32m   1046\u001B[0m     embeddings,\n\u001B[0;32m   1047\u001B[0m     embedding,\n\u001B[0;32m   1048\u001B[0m     metadatas\u001B[38;5;241m=\u001B[39mmetadatas,\n\u001B[0;32m   1049\u001B[0m     ids\u001B[38;5;241m=\u001B[39mids,\n\u001B[0;32m   1050\u001B[0m     \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[0;32m   1051\u001B[0m )\n",
      "File \u001B[1;32mD:\\ProgramData\\miniconda3\\envs\\pyth310\\lib\\site-packages\\langchain_community\\vectorstores\\faiss.py:1001\u001B[0m, in \u001B[0;36mFAISS.__from\u001B[1;34m(cls, texts, embeddings, embedding, metadatas, ids, normalize_L2, distance_strategy, **kwargs)\u001B[0m\n\u001B[0;32m    998\u001B[0m     index \u001B[38;5;241m=\u001B[39m faiss\u001B[38;5;241m.\u001B[39mIndexFlatIP(\u001B[38;5;28mlen\u001B[39m(embeddings[\u001B[38;5;241m0\u001B[39m]))\n\u001B[0;32m    999\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[0;32m   1000\u001B[0m     \u001B[38;5;66;03m# Default to L2, currently other metric types not initialized.\u001B[39;00m\n\u001B[1;32m-> 1001\u001B[0m     index \u001B[38;5;241m=\u001B[39m faiss\u001B[38;5;241m.\u001B[39mIndexFlatL2(\u001B[38;5;28mlen\u001B[39m(\u001B[43membeddings\u001B[49m\u001B[43m[\u001B[49m\u001B[38;5;241;43m0\u001B[39;49m\u001B[43m]\u001B[49m))\n\u001B[0;32m   1002\u001B[0m docstore \u001B[38;5;241m=\u001B[39m kwargs\u001B[38;5;241m.\u001B[39mpop(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mdocstore\u001B[39m\u001B[38;5;124m\"\u001B[39m, InMemoryDocstore())\n\u001B[0;32m   1003\u001B[0m index_to_docstore_id \u001B[38;5;241m=\u001B[39m kwargs\u001B[38;5;241m.\u001B[39mpop(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mindex_to_docstore_id\u001B[39m\u001B[38;5;124m\"\u001B[39m, {})\n",
      "\u001B[1;31mIndexError\u001B[0m: list index out of range"
     ]
    }
   ],
   "execution_count": 94
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 5 RAG(检索增强生成)",
   "id": "70d41799af132b5b"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-19T03:50:04.669536Z",
     "start_time": "2025-10-19T03:50:04.527840Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from langchain_core.prompts import PromptTemplate\n",
    "retriever = vector.as_retriever()\n",
    "retriever.search_kwargs = {\"k\": 3}\n",
    "docs = retriever.invoke(\"建设用地使用权是什么？\")\n",
    "# for i,doc in enumerate(docs):\n",
    "# print(f\"⭐第{i+1}条规定：\")\n",
    "# print(doc)\n",
    "# 6.定义提示词模版\n",
    "prompt_template = \"\"\"\n",
    "你是一个问答机器人。\n",
    "你的任务是根据下述给定的已知信息回答用户问题。\n",
    "确保你的回复完全依据下述已知信息。不要编造答案。\n",
    "如果下述已知信息不足以回答用户的问题，请直接回复\"我无法回答您的问题\"。\n",
    "已知信息:\n",
    "{info}\n",
    "用户问：\n",
    "{question}\n",
    "请用中文回答用户问题。\n",
    "\"\"\"\n",
    "# 7.得到提示词模版对象\n",
    "template = PromptTemplate.from_template(prompt_template)\n",
    "# 8.得到提示词对象\n",
    "prompt = template.format(info=docs, question='建设用地使用权是什么？')\n",
    "## 9. 调用LLM\n",
    "response = llm.invoke(prompt)\n",
    "print(response.content)"
   ],
   "id": "c901145fb91156d4",
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'vector' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[1;31mNameError\u001B[0m                                 Traceback (most recent call last)",
      "Cell \u001B[1;32mIn[96], line 2\u001B[0m\n\u001B[0;32m      1\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m\u001B[38;5;250m \u001B[39m\u001B[38;5;21;01mlangchain_core\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mprompts\u001B[39;00m\u001B[38;5;250m \u001B[39m\u001B[38;5;28;01mimport\u001B[39;00m PromptTemplate\n\u001B[1;32m----> 2\u001B[0m retriever \u001B[38;5;241m=\u001B[39m \u001B[43mvector\u001B[49m\u001B[38;5;241m.\u001B[39mas_retriever()\n\u001B[0;32m      3\u001B[0m retriever\u001B[38;5;241m.\u001B[39msearch_kwargs \u001B[38;5;241m=\u001B[39m {\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mk\u001B[39m\u001B[38;5;124m\"\u001B[39m: \u001B[38;5;241m3\u001B[39m}\n\u001B[0;32m      4\u001B[0m docs \u001B[38;5;241m=\u001B[39m retriever\u001B[38;5;241m.\u001B[39minvoke(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124m建设用地使用权是什么？\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n",
      "\u001B[1;31mNameError\u001B[0m: name 'vector' is not defined"
     ]
    }
   ],
   "execution_count": 96
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 6 使用Agent",
   "id": "8e73fb2a7a3002d4"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-19T23:47:56.064726Z",
     "start_time": "2025-10-19T23:47:46.696271Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from langchain.tools.retriever import create_retriever_tool\n",
    "# 检索器工具\n",
    "retriever_tool = create_retriever_tool(\n",
    "    retriever,\n",
    "    \"CivilCodeRetriever\",\n",
    "    \"搜索有关中华人民共和国民法典的信息。关于中华人民共和国民法典的任何问题，您必须使用此工具!\",\n",
    ")\n",
    "tools = [retriever_tool]\n",
    "from langchain import hub\n",
    "from langchain.agents import create_openai_functions_agent\n",
    "from langchain.agents import AgentExecutor\n",
    "# https://smith.langchain.com/hub\n",
    "prompt = hub.pull(\"hwchase17/openai-functions-agent\")\n",
    "agent = create_openai_functions_agent(llm, tools, prompt)\n",
    "agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)\n",
    "# 运行代理\n",
    "agent_executor.invoke({\"input\": \"建设用地使用权是什么\"})"
   ],
   "id": "9f23f756016a3a67",
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'retriever' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[1;31mNameError\u001B[0m                                 Traceback (most recent call last)",
      "Cell \u001B[1;32mIn[1], line 4\u001B[0m\n\u001B[0;32m      1\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m\u001B[38;5;250m \u001B[39m\u001B[38;5;21;01mlangchain\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mtools\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mretriever\u001B[39;00m\u001B[38;5;250m \u001B[39m\u001B[38;5;28;01mimport\u001B[39;00m create_retriever_tool\n\u001B[0;32m      2\u001B[0m \u001B[38;5;66;03m# 检索器工具\u001B[39;00m\n\u001B[0;32m      3\u001B[0m retriever_tool \u001B[38;5;241m=\u001B[39m create_retriever_tool(\n\u001B[1;32m----> 4\u001B[0m     \u001B[43mretriever\u001B[49m,\n\u001B[0;32m      5\u001B[0m     \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mCivilCodeRetriever\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[0;32m      6\u001B[0m     \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124m搜索有关中华人民共和国民法典的信息。关于中华人民共和国民法典的任何问题，您必须使用此工具!\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[0;32m      7\u001B[0m )\n\u001B[0;32m      8\u001B[0m tools \u001B[38;5;241m=\u001B[39m [retriever_tool]\n\u001B[0;32m      9\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m\u001B[38;5;250m \u001B[39m\u001B[38;5;21;01mlangchain\u001B[39;00m\u001B[38;5;250m \u001B[39m\u001B[38;5;28;01mimport\u001B[39;00m hub\n",
      "\u001B[1;31mNameError\u001B[0m: name 'retriever' is not defined"
     ]
    }
   ],
   "execution_count": 1
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
